package nio;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * Selector服务器端经典实例（通过telnet模拟客户端请求）
 * @Auther: luobiao
 * @Date: 2020/8/18 06:57
 * @Description:
 */
public class SelectSocketsTest {
    public static int port = 9999;
    private ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

    public static void main(String[] argv) throws Exception {
        new SelectSocketsTest().go(argv);
    }

    public void go(String[] argv) throws Exception {
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        ServerSocket serverSocket = serverChannel.socket();
        Selector selector = Selector.open();
        serverSocket.bind(new InetSocketAddress(port));
        serverChannel.configureBlocking(false);
        SelectionKey selectionKey = serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
            int n = selector.select();
            if (n == 0) {
                continue;
            }
            Iterator it = selector.selectedKeys().iterator();
            while (it.hasNext()) {
                SelectionKey key = (SelectionKey) it.next();
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel channel = server.accept();
                    registerChannel(selector, channel, SelectionKey.OP_READ);
                    sayHello(channel); //回复客户端消息
                }
                if (key.isReadable()) {//客户端发送过来的消息准备就绪可以读了
                    readDataFromSocket(key);
                }
                it.remove();//将已经处理的键移除
            }
        }
    }

    protected void registerChannel(Selector selector,SelectableChannel channel, int ops) throws Exception {
        if (channel == null) {
            return;
        }
        channel.configureBlocking(false);
        channel.register(selector, ops);
    }

    protected void readDataFromSocket(SelectionKey key) throws Exception {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        int count;
        buffer.clear();
        while ((count = socketChannel.read(buffer)) > 0) {
            buffer.flip();
            while (buffer.hasRemaining()) {
                socketChannel.write(buffer);
            }
            buffer.clear();
        }
        if (count < 0) {
            socketChannel.close();
        }
    }

   private void sayHello(SocketChannel channel) throws Exception {
       buffer.clear();
       buffer.put("Hi there!\r\n".getBytes());
       buffer.flip();
       channel.write(buffer);
   }
}
